package com.basic.framework.aspectj;

import com.basic.common.annotation.FileExport;
import com.basic.common.config.BasicConfig;
import com.basic.common.constant.Constants;
import com.basic.common.enums.BusinessStatus;
import com.basic.common.utils.DateUtils;
import com.basic.common.utils.SecurityUtils;
import com.basic.common.utils.StringUtils;
import com.basic.common.utils.file.FileUtils;
import com.basic.common.websocket.WebSocketUsers;
import com.basic.framework.manager.AsyncManager;
import com.basic.framework.manager.factory.AsyncFactory;
import com.basic.tool.domain.SysDownloadCenter;
import org.apache.commons.codec.digest.DigestUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.core.NamedThreadLocal;
import org.springframework.stereotype.Component;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.util.HashMap;
import java.util.Map;

/**
 * Excel导出处理
 *
 * @author zhaoxy_jn@163.com
 */
@Aspect
@Component
public class FileExportAspect {

    private static final Map<String, String> extensionMap = new HashMap<>();

    static {
        // 初始化文件扩展名与数字的映射
        extensionMap.put("xlsx", "1");
        extensionMap.put("xls", "1");
        extensionMap.put("docx", "2");
        extensionMap.put("doc", "2");
        extensionMap.put("pptx", "3");
        extensionMap.put("ppt", "3");
        extensionMap.put("pdf", "4");
        extensionMap.put("txt", "5");
    }

    /** 记录线程变量 */
    private static final ThreadLocal<SysDownloadCenter> CENTER_THREADLOCAL = new NamedThreadLocal<>("SysDownloadCenter");

    /**
     * 处理请求前执行
     * 将任务信息存储到下载中心
     */
    @Before(value = "@annotation(controllerFileExport)")
    public void boBefore(JoinPoint joinPoint, FileExport controllerFileExport) {
        SysDownloadCenter center = new SysDownloadCenter();
        center.setFileName(controllerFileExport.fileName());
        center.setFileType(extensionMap.getOrDefault(FileUtils.getFileSuffix(controllerFileExport.fileName()), "-1"));
        center.setBuildStartTime(DateUtils.getNowDate());
        center.setCreateBy(SecurityUtils.getUsername());
        center.setUserId(SecurityUtils.getUserId());
        center.setDeptId(SecurityUtils.getDeptId());
        AsyncManager.me().execute(AsyncFactory.insertDownloadCenter(center));
        CENTER_THREADLOCAL.set(center);
    }

    /**
     * 处理完请求后执行
     */
    @AfterReturning(pointcut = "@annotation(controllerFileExport)", returning = "jsonResult")
    public void doAfterReturning(JoinPoint joinPoint, FileExport controllerFileExport, Object jsonResult) throws IOException {
        SysDownloadCenter center = CENTER_THREADLOCAL.get();
        // 文件生成结束时间
        center.setBuildEndTime(DateUtils.getNowDate());
        // 文件路径
        center.setFileUrl(jsonResult.toString());

        File file = new File(BasicConfig.getProfile() + StringUtils.substringAfter(center.getFileUrl(), Constants.RESOURCE_PREFIX));
        updateFileInfo(center, file);
        // 文件状态
        center.setFileStatus("1");
        // 更新人
        center.setUpdateBy(SecurityUtils.getUsername());
        // 保存数据库
        AsyncManager.me().execute(AsyncFactory.updateDownloadCenter(center));
    }

    /**
     * 拦截异常操作
     *
     * @param joinPoint 切点
     * @param e 异常
     */
    @AfterThrowing(value = "@annotation(controllerFileExport)", throwing = "e")
    public void doAfterThrowing(JoinPoint joinPoint, FileExport controllerFileExport, Exception e)
    {
        SysDownloadCenter center = CENTER_THREADLOCAL.get();
        // 文件状态
        center.setFileStatus("-1");
        // 更新人
        center.setUpdateBy(SecurityUtils.getUsername());
        // 保存数据库
        AsyncManager.me().execute(AsyncFactory.updateDownloadCenter(center));
        // 任务结束，发送消息
        WebSocketUsers.sendMessageToUserByText(SecurityUtils.getUserId(), center.getFileName() + "文件生成失败，请联系管理员", BusinessStatus.FAIL);
    }

    private void updateFileInfo(SysDownloadCenter center, File file) throws IOException {
        try (InputStream in = Files.newInputStream(file.toPath())) {
            center.setFileSize(FileUtils.getFileSize(file));
            center.setFileMd5(DigestUtils.md5Hex(in).toUpperCase());
        }
    }
}
